package win.larryzeal.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * nio model - socket programming
 * <p>
 * Created by LarryZeal on 2017/9/18.
 */
public class NioSocketDemo {
    public static void main(String[] args) throws IOException{
        NioSocketDemo demo = new NioSocketDemo();
        demo.init(6379);
        demo.listenSelector();

    }

    private Selector selector;// channel selector (manager)

    public void init(int port) throws IOException{
        ServerSocketChannel channel = ServerSocketChannel.open();
        channel.configureBlocking(false);// note this
        channel.socket().bind(new InetSocketAddress(port));

        selector = Selector.open();

        //bind channel with selector
        channel.register(selector, SelectionKey.OP_ACCEPT); //nio里面事件有4种

        System.out.println("服务已启动...");
    }

    public void listenSelector() throws IOException{
        //轮询监听selector
        while(true){
            //等待客户端连接
            selector.select();//调用os的多路复用模型
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while(iterator.hasNext()){
                SelectionKey selectionKey = iterator.next();
                iterator.remove();
                //处理请求
                handle(selectionKey);
            }
        }
    }

    /**
     * 处理客户端请求
     *
     * @param selectionKey
     */
    private void handle(SelectionKey selectionKey) throws IOException{
        if(selectionKey.isAcceptable()){
            // 处理客户端连接请求事件
            ServerSocketChannel channel = (ServerSocketChannel) selectionKey.channel();
            SocketChannel socketChannel = channel.accept();

            socketChannel.configureBlocking(false); // KEY POINT
            //接收客户端发送的信息时，需要给通道设置读权限
            socketChannel.register(selector, SelectionKey.OP_READ);
        } else if(selectionKey.isReadable()){
            // 处理读的事件
            ServerSocketChannel channel = (ServerSocketChannel) selectionKey.channel();
            SocketChannel socketChannel = channel.accept();

            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int len = socketChannel.read(buffer);
            if(len > 0){
                String info = new String(buffer.array(), 0, len, "gbk");
                System.out.println("got data: " + info);
            } else{
                System.out.println("客户端关闭了...");
                selectionKey.cancel();
            }

        }
    }

}
